Author: Sanjana Ramankandath (sramankandath@scu.edu) Title: Project 3: Review of Amazon Products Data: https://www.kaggle.com/datafiniti/consumer-reviews-of-amazon-products#Datafiniti_Amazon_Consumer_Reviews_of_Amazon_Products_May19.csv
In this project, we will analyze the customer review data set of Amazon products. The dataset has > 20K records with several columns including product ratings, submission date, category etc., Using this data set, we are going to analyze the top reviewed product categories, how each product is rated based on it’s description, pattern in which each item is sold and finally how these categories compete against each other with respect to the user-ratings.
First let’s get the data from the csv file. The working directory is assumed to contain the csv file that will be uploaded along with this notebook.
# Get the dataset - Uncomment and modify based on the data source.
# getwd()
# setwd("/Users/sanjana.ramankandath/Documents/Personal/AmmuMasters/SantaClara_BA/Amazon")
amazon_review_data_feb_apr_2019 <- read.csv("Datafiniti_Amazon_Consumer_Reviews_of_Amazon_Products_May19.csv")
amazon_review_data_feb_apr_2019
First, let us group the data set based on the name and cleanse the data by removing unwanted description from the name. This helps in displaying concise information in the graphs/plots.
# Identify the unique list of products for each time period
library(dplyr)
amazon_review_data_feb_apr_2019 %>% group_by(name) %>% tally() -> top_data_feb_apr_2019
sorted_data_feb_apr_2019 <- top_data_feb_apr_2019[order(top_data_feb_apr_2019$n, decreasing = TRUE),]
# Now in order to group same items in the data, there is no unique column because the data
# doesn't have it. Let us use common filters to filter the data. Since each seller can post
# the same item on sale using a different name, the only way to filter them is to use the
# common name used for all products. Remove fluff/unwanted words from the name to preven the bar
# plot from showing too much text.
library(stringr)
common_fluff_string = "- Includes Special Offers|All-New| E-reader|6 High-Resolution Display (300 ppi), Wi-Fi|with Adaptive Built-in Light, PagePress Sensors, Wi-Fi|Waterproof, Built-In Audible, 32 GB, Wi-Fi + Free Cellular Connectivity| (Fits Latest Generation Kindle and Kindle DX) For shipment in the U.S only|8 HD Display, Wi-Fi, |7 Display,|Silver Aluminum|High-Resolution Display (300 ppi), Wi-Fi| 6 High-Resolution Display (300 ppi), Wi-Fi"
# Get the first and most popular item - AmazonBasics batteries
batteries <- dplyr::filter(sorted_data_feb_apr_2019, grepl("Batteries|battery|batteries",name))
# Each category might have different strings to be removed. Remove each one of them from each category
batteries$name<-str_replace_all(batteries$name, "AmazonBasics AA|AAA|A| Performance Alkaline Batteries|Packaging May Vary", "")
batteries$name <- str_replace_all(batteries$name, common_fluff_string, "")
batteries$category <- "Batteries"
# Get the data for Fire tablets.
fire <- dplyr::filter(sorted_data_feb_apr_2019, grepl("Fire|fire", name))
fire$category <- "Fire"
fire$name <- str_replace_all(fire$name, "Edition Tablet|8 Tablet with Alexa, 8 HD Display, | - with Special Offers|-Proof Case|- Includes Special Offers,|All-New ","")
fire$name <- str_replace_all(fire$name, common_fluff_string, "")
# There are too many tablet records with bare minimum reviews, let's consider the top 20.
fire <-head(fire, 20)
# Similarly, get the data for Kindle and filter out the words.
kindle <- dplyr::filter(sorted_data_feb_apr_2019, grepl("Kindle|kindle|E-reader", name))
kindle$category <- "Kindle"
kindle$name <- str_replace_all(kindle$name, common_fluff_string,"")
kindle$name <- str_replace_all(kindle$name, "High-Resolution Display|(300 ppi)|Wi-Fi|Free Cellular Connectivity| and Power Adapter for Fire Tablets and Kindle eReaders|Power Adapter Wall Charger And Usb Cable Micro Usb Cord|PagePress Sensors, Free 3G", "")
kindle$name <- str_replace_all(kindle$name, "(Fits Latest Generation Kindle and Kindle DX)| For shipment in the U.S only|International Charging Kit|(for accelerated charging in over 200 countries)|Wall Travel Charger Fire|micro Usb Cable|Glare-Free Touchscreen Display|()", "")
# Filter unwanted words out of Amazon Echo product.
echo <- dplyr::filter(sorted_data_feb_apr_2019, grepl("Echo|Smart Assistant|echo", name))
echo$category <- "Echo"
power_adapter <- dplyr::filter(sorted_data_feb_apr_2019, grepl("Power|Charger|power", name))
power_adapter$category <- "power_adapter"
power_adapter$name <- str_replace_all(power_adapter$name, common_fluff_string, "")
Observation 1:
Now that we have 5 top datasets isolated based on the category, let us plot the number of reviews for each category. In this graph, it is clearly evident that one of the most popular amazon item is the batteries that Amazon provides as a part of AmazonBasics category line. This is not unusual since AmazonBasics batteries are some of the best when we compare it with competing products in similar price range. Fire Tablets is also quite popular in reviews. Amazon echo is not quite popular but this can be attributed to the time of data set since Voice Automation wasn’t prevalent back then. Kindle is another decent product which has fairly high number of ratings too.
# Set the appropriate themes for the plot.
library(ggplot2)
theme_set(
theme_minimal() +
theme(legend.position = "center")
)
library(RColorBrewer)
# Plot the top reviewed items along with their category. Category names are too big to be displayed in the same chart.
# In order to get a stacked bar plot, the following reference was used to get the idea - http://rstudio-pubs-static.s3.amazonaws.com/3256_bb10db1440724dac8fa40da5e658ada5.html
table_with_individual_categories <- rbind(batteries, fire, kindle, echo, power_adapter)
top_reviewed_data_plot <- ggplot(data = table_with_individual_categories, aes(x = table_with_individual_categories$category, y = n,fill=table_with_individual_categories$category)) + geom_bar(stat="identity")
top_reviewed_data_plot + scale_fill_brewer(palette = "Blues")

Observation 2:
In order to analyze closely if certain sub-categories has an impact in the overall barplot, we consider two categories from the above(Fire Tablets and Kindle) and analyze the percentage composition of sub-categories based on the name provided. A lot of sellers provide detailed description within the name which acts as a propellant for certain items to be sold more than the rest. For example in Fire tablet sale, the most popular item seems to be the 16GB tablet followed closely by tablets specific for Kids (Fire Kids). This provides a hint that a lot of consumers buy Fire tablets for their kids and also buy it with minimal config (16GB) compared to the maximum configuration provided(32G).
# Calculate the percentage of each name based on the top few rows
top_10_fire_tablet_reviews = head(fire, 10)
top_10_fire_tablet_reviews$percentage <- (top_10_fire_tablet_reviews$n / sum(top_10_fire_tablet_reviews$n) * 100.0)
top_10_fire_tablet_reviews
# Create a pie chart with the top 10 fire tablet reviews. Format/color of the pie chart from https://www.r-bloggers.com/how-to-make-a-pie-chart-in-r/
pie_fire_tablet = ggplot(top_10_fire_tablet_reviews, aes(x="", y=percentage, fill=name)) + geom_bar(stat="identity", width=1) + coord_polar("y", start=0) + geom_text(aes(label = paste0(round(percentage), "%")), position = position_stack(vjust = 0.5)) + labs(x = NULL, y = NULL, fill = NULL, title = "Fire Tablets") + theme_classic() + theme(axis.line = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
plot.title = element_text(hjust = 0.5, color = "#666666"))
pie_fire_tablet

Observation 3:
Similarly for Kindle product, Kindle Voyage seems to be the most popular in this time frame followed by the Kindle version which comes in white. Sellers who sell kindle along with a cover (Leather Charging Cover) seem to benefit as well.
# Now let's do the same for kindle - Computing the composition of reviewes for kindle product.
kindle$percentage <- kindle$n / sum(kindle$n) * 100
kindle
pie_kindle = ggplot(kindle, aes(x="", y=percentage, fill=name)) + geom_bar(stat="identity", width=1) + coord_polar("y", start=0) + labs(x = NULL, y = NULL, fill = NULL, title = "Kindle") + theme_classic() + theme(axis.line = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank(),
plot.title = element_text(hjust = 0.5, color = "#777777"))
pie_kindle

Observation 4:
Let us analyze AmazonBasics batteries which seem to be quite popular with consumers. There are two categories sold (AA and AAA) and both of them are high sellers. We are going to check whether the ratings for batteries varies according to the time of the year. This is based on the column which has the date when the product was reviewed. One assumption that we make here is that a customer who buys a product from Amazon is likely to receive an email to submit a review within the first few weeks and submit one shortly after receiving it. From the plots, we can see two observations
- This product took a little time to be popular owing to the lack of reviews initially.
- The product is quite popular during the holidays.
# Now for the top rated item, AmazonBasics batteries, let us check the review rate and see if the reviews are distributed over time
all_battery_reviews <- dplyr::filter(amazon_review_data_feb_apr_2019, grepl("Performance Alkaline Batteries",name))
# We are only concerned with review date and ratings for these products
# To group the reviews on a monthly basis, let's clean the timestamp before grouping them
install.packages("lubridate")
Error in install.packages : Updating loaded packages
library(lubridate)
all_battery_reviews %>% select(name, reviews.date) -> battery_review_date
battery_review_date$reviews.date <- as.Date(battery_review_date$reviews.date)
battery_review_date %>% arrange(reviews.date) -> sorted_battery_review_date
# For each review, let us add a column to indicate the count of review. As we group the reviews based on month and year, these will be accumulated
sorted_battery_review_date$num_reviews <- 1
# Group the reviews based on timerange - source: https://stackoverflow.com/questions/33221425/how-do-i-group-my-date-variable-into-month-year-in-r/33221885
sorted_battery_review_date %>% mutate(month = format(reviews.date, "%m"), year = format(reviews.date, "%Y")) %>%
group_by(month, year) -> battery_reviews_in_order
# Since we grouped the review count, the sorted data is now unsorted. Let's sort them to display the timeline. Since we are focused on the month, we will treat the 1st of each month in our calculation based on the month and the year the review is set.
battery_reviews_in_order %>% summarise(num_reviews=sum(num_reviews)) -> battery_reviews_per_month
battery_reviews_per_month$Date <- paste(battery_reviews_per_month$year, battery_reviews_per_month$month, "01", sep="-")
battery_reviews_per_month$Date <- as.Date(battery_reviews_per_month$Date, "%Y-%m-%d")
battery_reviews_per_month %>% arrange(Date) -> sorted_battery_reviews_based_on_date
sorted_battery_reviews_based_on_date$activity <-
ifelse(sorted_battery_reviews_based_on_date$num_reviews < 40, "Low",
ifelse(sorted_battery_reviews_based_on_date$num_reviews > 40 &
sorted_battery_reviews_based_on_date$num_reviews < 200, "Mid",
ifelse(sorted_battery_reviews_based_on_date$num_reviews > 200 &
sorted_battery_reviews_based_on_date$num_reviews < 350 , "High",
ifelse(sorted_battery_reviews_based_on_date$num_reviews < 1000, "Very_High",""))))
# Plotting a timeline was referenced using http://benalexkeen.com/creating-a-timeline-graphic-using-r-and-ggplot2/ which used project timelines. We use similar strategy to compare the numebr of reviews that was recorded per month.
review_levels <- c("Low", "Mid", "High", "Very_High")
status_colors <- c("#0070C0", "#00B050", "#FFC000", "#C00000")
sorted_battery_reviews_based_on_date$activity <- factor(sorted_battery_reviews_based_on_date$activity, levels=review_levels)
sorted_battery_reviews_based_on_date
# Variability of reviews on a plot shows that the product is quite popular during the holidays.
install.packages("hrbrthemes")
trying URL 'https://cran.rstudio.com/bin/windows/contrib/3.6/hrbrthemes_0.6.0.zip'
Content type 'application/zip' length 1900773 bytes (1.8 MB)
downloaded 1.8 MB
package ‘hrbrthemes’ successfully unpacked and MD5 sums checked
The downloaded binary packages are in
C:\Users\Sanjana\AppData\Local\Temp\RtmpW2vIK6\downloaded_packages
install.packages("lubridate")
Warning in install.packages :
package ‘lubridate’ is in use and will not be installed
battery_plot <- ggplot(data = sorted_battery_reviews_based_on_date, aes(x = sorted_battery_reviews_based_on_date$Date, y = sorted_battery_reviews_based_on_date$num_reviews)) + geom_point(stat="identity") + geom_line(color="#e9ecef")+ ggtitle("AmazonBasics Batteries", subtitle="Review rate over time") + theme(plot.title = element_text(hjust = 0.5)) + theme(plot.subtitle = element_text(hjust = 0.5))
battery_plot

Observation 5:
Similarly, for Fire Tablets, if we plot the reviews according to the timeline, we can see that the tablets are very popular during the holidays. These tablets are quite popular primarily because of their price point (relatively cheap compared to its main competitor- Apple Ipad) and the target demographic for these tablets, which is focussed towards kids during the holidays as a gift (based on the earlier pie chart).
# Now do the same for Fire Tablets
all_fire_reviews <- dplyr::filter(amazon_review_data_feb_apr_2019, grepl("Fire|fire", name))
all_fire_reviews %>% select(name, reviews.date) -> fire_review_date
fire_review_date$reviews.date <- as.Date(fire_review_date$reviews.date)
fire_review_date %>% arrange(reviews.date) -> sorted_fire_review_date
# For each review, let us add a column to indicate the count of review. As we group the reviews based on month and year, these will be accumulated
sorted_fire_review_date$num_reviews <- 1
# Group the reviews based on timeline - source: https://stackoverflow.com/questions/33221425/how-do-i-group-my-date-variable-into-month-year-in-r/33221885
sorted_fire_review_date %>% mutate(month = format(reviews.date, "%m"), year = format(reviews.date, "%Y")) %>%
group_by(month, year) -> fire_reviews_in_order
# Since we grouped the review count, the sorted data is now unsorted. Let's sort them to display the timeline. Since we are focused on the month, we will treat the 1st of each month in our calculation based on the month and the year the review is set.
fire_reviews_in_order %>% summarise(num_reviews=sum(num_reviews)) -> fire_reviews_per_month
fire_reviews_per_month$Date <- paste(fire_reviews_per_month$year, fire_reviews_per_month$month, "01", sep="-")
fire_reviews_per_month$Date <- as.Date(fire_reviews_per_month$Date, "%Y-%m-%d")
fire_reviews_per_month %>% arrange(Date) -> sorted_fire_reviews_per_month
sorted_fire_reviews_per_month
# Variability of reviews
fire_plot <- ggplot(data = sorted_fire_reviews_per_month, aes(x = sorted_fire_reviews_per_month$Date, y = sorted_fire_reviews_per_month$num_reviews)) + geom_point(stat="identity", color="navyblue") + geom_line(color="#e9ecef")+ ggtitle("Fire Tablets", subtitle="Review rate over time") + theme(plot.title = element_text(hjust = 0.5)) + theme(plot.subtitle = element_text(hjust = 0.5))
fire_plot

Observation 6:
Data for Kindle tablets is not as predictable as the earlier categories since the reviews are spread over the year. Kindle is a great product for E-readers and the target demographic is not quite narrow. In addition to Kindle E-readers, this data set also includes power-adapters for Kindle readers which could have skewed the results.
# Similar workflow for Kindle product
all_kindle_reviews <- dplyr::filter(amazon_review_data_feb_apr_2019, grepl("Kindle|kindle|E-reader", name))
all_kindle_reviews %>% select(name, reviews.date) -> kindle_review_date
kindle_review_date$reviews.date <- as.Date(kindle_review_date$reviews.date)
kindle_review_date %>% arrange(reviews.date) -> sorted_kindle_review_date
# For each review, let us add a column to indicate the count of review. As we group the reviews based on month and year, these will be accumulated
sorted_kindle_review_date$num_reviews <- 1
# Group the reviews based on timeline - source: https://stackoverflow.com/questions/33221425/how-do-i-group-my-date-variable-into-month-year-in-r/33221885
sorted_kindle_review_date %>% mutate(month = format(reviews.date, "%m"), year = format(reviews.date, "%Y")) %>%
group_by(month, year) -> kindle_reviews_in_order
# Since we grouped the review count, the sorted data is now unsorted. Let's sort them to display the timeline. Since we are focused on the month, we will treat the 1st of each month in our calculation based on the month and the year the review is set.
kindle_reviews_in_order %>% summarise(num_reviews=sum(num_reviews)) -> kindle_reviews_per_month
kindle_reviews_per_month$Date <- paste(kindle_reviews_per_month$year, kindle_reviews_per_month$month, "01", sep="-")
kindle_reviews_per_month$Date <- as.Date(kindle_reviews_per_month$Date, "%Y-%m-%d")
kindle_reviews_per_month %>% arrange(Date) -> sorted_kindle_reviews_per_month
sorted_kindle_reviews_per_month
# Variability of reviews
kindle_plot <- ggplot(data = sorted_kindle_reviews_per_month, aes(x = sorted_kindle_reviews_per_month$Date, y = sorted_kindle_reviews_per_month$num_reviews)) + geom_point(stat="identity", color="springgreen3") + geom_line(color="#e9ecef")+ ggtitle("Amazon Kindle", subtitle="Review rate over time") + theme(plot.title = element_text(hjust = 0.5)) + theme(plot.subtitle = element_text(hjust = 0.5))
kindle_plot

Observation 7:
Now let us compare the ratings for each of these categories and plot variability in which users are likely to provide a better rating for certain product. Based on the filtered data set, Fire Tablets have quite a large number of “4” ratings while Kindle and batteries have high number of consumers giving it “5” out of “5”. The usability of Fire tablets could be one of the reason for this observation. One other observation that was found here is that batteries have more number of unsatisfied customers who provided “1”. If we analyze some of these ratings, a lot of it is due to the defective product that gets shipped and also the lifetime of a battery. While Amazon is likely to accept such items as Returns and provide a new one, a customer is unlikely to submit/edit his already completed review.
# Comparing review ratings of various product categories.
all_fire_reviews %>% select(name, reviews.rating) -> all_fire_reviews_ratings
all_kindle_reviews %>% select(name, reviews.rating) -> all_kindle_reviews_ratings
all_battery_reviews %>% select(name, reviews.rating) -> all_battery_reviews_ratings
# Now plot a density graph with each category.
all_fire_reviews_ratings$Item = "Amazon Fire"
all_kindle_reviews_ratings$Item = "Amazon Kindle"
all_battery_reviews_ratings$Item = "Amazon Batteries"
combined_reviews <- rbind(all_fire_reviews_ratings,all_kindle_reviews_ratings,all_battery_reviews_ratings)
ggplot(combined_reviews, aes(reviews.rating, fill = Item)) + geom_density(alpha = 0.5, position = 'identity') + theme(legend.position="right") + ggtitle("Comparison of User Ratings") + theme(plot.title = element_text(hjust = 0.5))

All the analysis and graphs posted above provide some interesting and useful information with respect to Amazon supplied products and the consumer behavior when it comes to purchasing (popularity based on the time). Unlike the general perception, Few amazon products like Fire tablets are quite popular and targeted towards a niche segment and sold very frequently during the holidays.
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpBdXRob3I6IFNhbmphbmEgUmFtYW5rYW5kYXRoIChzcmFtYW5rYW5kYXRoQHNjdS5lZHUpDQpUaXRsZTogUHJvamVjdCAzOiBSZXZpZXcgb2YgQW1hem9uIFByb2R1Y3RzDQpEYXRhOiBodHRwczovL3d3dy5rYWdnbGUuY29tL2RhdGFmaW5pdGkvY29uc3VtZXItcmV2aWV3cy1vZi1hbWF6b24tcHJvZHVjdHMjRGF0YWZpbml0aV9BbWF6b25fQ29uc3VtZXJfUmV2aWV3c19vZl9BbWF6b25fUHJvZHVjdHNfTWF5MTkuY3N2DQogDQpJbiB0aGlzIHByb2plY3QsIHdlIHdpbGwgYW5hbHl6ZSB0aGUgY3VzdG9tZXIgcmV2aWV3IGRhdGEgc2V0IG9mIEFtYXpvbiBwcm9kdWN0cy4gVGhlIGRhdGFzZXQgaGFzID4gMjBLIHJlY29yZHMgd2l0aCBzZXZlcmFsIGNvbHVtbnMgaW5jbHVkaW5nIHByb2R1Y3QgcmF0aW5ncywgc3VibWlzc2lvbiBkYXRlLCBjYXRlZ29yeSBldGMuLCBVc2luZyB0aGlzIGRhdGEgc2V0LCB3ZSBhcmUgZ29pbmcgdG8gYW5hbHl6ZSB0aGUgdG9wIHJldmlld2VkIHByb2R1Y3QgY2F0ZWdvcmllcywgaG93IGVhY2ggcHJvZHVjdCBpcyByYXRlZCBiYXNlZCBvbiBpdCdzIGRlc2NyaXB0aW9uLCBwYXR0ZXJuIGluIHdoaWNoIGVhY2ggaXRlbSBpcyBzb2xkIGFuZCBmaW5hbGx5IGhvdyB0aGVzZSBjYXRlZ29yaWVzIGNvbXBldGUgYWdhaW5zdCBlYWNoIG90aGVyIHdpdGggcmVzcGVjdCB0byB0aGUgdXNlci1yYXRpbmdzLg0KDQpGaXJzdCBsZXQncyBnZXQgdGhlIGRhdGEgZnJvbSB0aGUgY3N2IGZpbGUuIFRoZSB3b3JraW5nIGRpcmVjdG9yeSBpcyBhc3N1bWVkIHRvIGNvbnRhaW4gdGhlIGNzdiBmaWxlIHRoYXQgd2lsbCBiZSB1cGxvYWRlZCBhbG9uZyB3aXRoIHRoaXMgbm90ZWJvb2suDQoNCmBgYHtyfQ0KIyBHZXQgdGhlIGRhdGFzZXQgLSBVbmNvbW1lbnQgYW5kIG1vZGlmeSBiYXNlZCBvbiB0aGUgZGF0YSBzb3VyY2UuDQojIGdldHdkKCkNCiMgc2V0d2QoIi9Vc2Vycy9zYW5qYW5hLnJhbWFua2FuZGF0aC9Eb2N1bWVudHMvUGVyc29uYWwvQW1tdU1hc3RlcnMvU2FudGFDbGFyYV9CQS9BbWF6b24iKQ0KYW1hem9uX3Jldmlld19kYXRhX2ZlYl9hcHJfMjAxOSA8LSByZWFkLmNzdigiRGF0YWZpbml0aV9BbWF6b25fQ29uc3VtZXJfUmV2aWV3c19vZl9BbWF6b25fUHJvZHVjdHNfTWF5MTkuY3N2IikNCmFtYXpvbl9yZXZpZXdfZGF0YV9mZWJfYXByXzIwMTkNCg0KYGBgDQoNCkZpcnN0LCBsZXQgdXMgZ3JvdXAgdGhlIGRhdGEgc2V0IGJhc2VkIG9uIHRoZSBuYW1lIGFuZCBjbGVhbnNlIHRoZSBkYXRhIGJ5IHJlbW92aW5nIHVud2FudGVkIGRlc2NyaXB0aW9uIGZyb20gdGhlIG5hbWUuIFRoaXMgaGVscHMgaW4gZGlzcGxheWluZyBjb25jaXNlIGluZm9ybWF0aW9uIGluIHRoZSBncmFwaHMvcGxvdHMuIA0KDQpgYGB7cn0NCiMgSWRlbnRpZnkgdGhlIHVuaXF1ZSBsaXN0IG9mIHByb2R1Y3RzIGZvciBlYWNoIHRpbWUgcGVyaW9kIA0KbGlicmFyeShkcGx5cikNCmFtYXpvbl9yZXZpZXdfZGF0YV9mZWJfYXByXzIwMTkgJT4lIGdyb3VwX2J5KG5hbWUpICU+JSB0YWxseSgpIC0+IHRvcF9kYXRhX2ZlYl9hcHJfMjAxOQ0Kc29ydGVkX2RhdGFfZmViX2Fwcl8yMDE5IDwtIHRvcF9kYXRhX2ZlYl9hcHJfMjAxOVtvcmRlcih0b3BfZGF0YV9mZWJfYXByXzIwMTkkbiwgZGVjcmVhc2luZyA9IFRSVUUpLF0NCg0KIyBOb3cgaW4gb3JkZXIgdG8gZ3JvdXAgc2FtZSBpdGVtcyBpbiB0aGUgZGF0YSwgdGhlcmUgaXMgbm8gdW5pcXVlIGNvbHVtbiBiZWNhdXNlIHRoZSBkYXRhDQojIGRvZXNuJ3QgaGF2ZSBpdC4gTGV0IHVzIHVzZSBjb21tb24gZmlsdGVycyB0byBmaWx0ZXIgdGhlIGRhdGEuIFNpbmNlIGVhY2ggc2VsbGVyIGNhbiBwb3N0DQojIHRoZSBzYW1lIGl0ZW0gb24gc2FsZSB1c2luZyBhIGRpZmZlcmVudCBuYW1lLCB0aGUgb25seSB3YXkgdG8gZmlsdGVyIHRoZW0gaXMgdG8gdXNlIHRoZQ0KIyBjb21tb24gbmFtZSB1c2VkIGZvciBhbGwgcHJvZHVjdHMuIFJlbW92ZSBmbHVmZi91bndhbnRlZCB3b3JkcyBmcm9tIHRoZSBuYW1lIHRvIHByZXZlbiB0aGUgYmFyDQojIHBsb3QgZnJvbSBzaG93aW5nIHRvbyBtdWNoIHRleHQuDQpsaWJyYXJ5KHN0cmluZ3IpDQpjb21tb25fZmx1ZmZfc3RyaW5nID0gIi0gSW5jbHVkZXMgU3BlY2lhbCBPZmZlcnN8QWxsLU5ld3wgRS1yZWFkZXJ8NiBIaWdoLVJlc29sdXRpb24gRGlzcGxheSAoMzAwIHBwaSksIFdpLUZpfHdpdGggQWRhcHRpdmUgQnVpbHQtaW4gTGlnaHQsIFBhZ2VQcmVzcyBTZW5zb3JzLCBXaS1GaXxXYXRlcnByb29mLCBCdWlsdC1JbiBBdWRpYmxlLCAzMiBHQiwgV2ktRmkgKyBGcmVlIENlbGx1bGFyIENvbm5lY3Rpdml0eXwgKEZpdHMgTGF0ZXN0IEdlbmVyYXRpb24gS2luZGxlIGFuZCBLaW5kbGUgRFgpIEZvciBzaGlwbWVudCBpbiB0aGUgVS5TIG9ubHl8OCBIRCBEaXNwbGF5LCBXaS1GaSwgfDcgRGlzcGxheSx8U2lsdmVyIEFsdW1pbnVtfEhpZ2gtUmVzb2x1dGlvbiBEaXNwbGF5ICgzMDAgcHBpKSwgV2ktRml8IDYgSGlnaC1SZXNvbHV0aW9uIERpc3BsYXkgKDMwMCBwcGkpLCBXaS1GaSINCg0KIyBHZXQgdGhlIGZpcnN0IGFuZCBtb3N0IHBvcHVsYXIgaXRlbSAtIEFtYXpvbkJhc2ljcyBiYXR0ZXJpZXMNCmJhdHRlcmllcyA8LSBkcGx5cjo6ZmlsdGVyKHNvcnRlZF9kYXRhX2ZlYl9hcHJfMjAxOSwgZ3JlcGwoIkJhdHRlcmllc3xiYXR0ZXJ5fGJhdHRlcmllcyIsbmFtZSkpDQoNCiMgRWFjaCBjYXRlZ29yeSBtaWdodCBoYXZlIGRpZmZlcmVudCBzdHJpbmdzIHRvIGJlIHJlbW92ZWQuIFJlbW92ZSBlYWNoIG9uZSBvZiB0aGVtIGZyb20gZWFjaCBjYXRlZ29yeQ0KYmF0dGVyaWVzJG5hbWU8LXN0cl9yZXBsYWNlX2FsbChiYXR0ZXJpZXMkbmFtZSwgIkFtYXpvbkJhc2ljcyBBQXxBQUF8QXwgUGVyZm9ybWFuY2UgQWxrYWxpbmUgQmF0dGVyaWVzfFBhY2thZ2luZyBNYXkgVmFyeSIsICIiKQ0KYmF0dGVyaWVzJG5hbWUgPC0gc3RyX3JlcGxhY2VfYWxsKGJhdHRlcmllcyRuYW1lLCBjb21tb25fZmx1ZmZfc3RyaW5nLCAiIikNCmJhdHRlcmllcyRjYXRlZ29yeSA8LSAiQmF0dGVyaWVzIg0KDQojIEdldCB0aGUgZGF0YSBmb3IgRmlyZSB0YWJsZXRzLg0KZmlyZSA8LSBkcGx5cjo6ZmlsdGVyKHNvcnRlZF9kYXRhX2ZlYl9hcHJfMjAxOSwgZ3JlcGwoIkZpcmV8ZmlyZSIsIG5hbWUpKQ0KZmlyZSRjYXRlZ29yeSA8LSAiRmlyZSINCmZpcmUkbmFtZSA8LSBzdHJfcmVwbGFjZV9hbGwoZmlyZSRuYW1lLCAiRWRpdGlvbiBUYWJsZXR8OCBUYWJsZXQgd2l0aCBBbGV4YSwgOCBIRCBEaXNwbGF5LCB8IC0gd2l0aCBTcGVjaWFsIE9mZmVyc3wtUHJvb2YgQ2FzZXwtIEluY2x1ZGVzIFNwZWNpYWwgT2ZmZXJzLHxBbGwtTmV3ICIsIiIpDQpmaXJlJG5hbWUgPC0gc3RyX3JlcGxhY2VfYWxsKGZpcmUkbmFtZSwgY29tbW9uX2ZsdWZmX3N0cmluZywgIiIpDQojIFRoZXJlIGFyZSB0b28gbWFueSB0YWJsZXQgcmVjb3JkcyB3aXRoIGJhcmUgbWluaW11bSByZXZpZXdzLCBsZXQncyBjb25zaWRlciB0aGUgdG9wIDIwLg0KZmlyZSA8LWhlYWQoZmlyZSwgMjApDQoNCiMgU2ltaWxhcmx5LCBnZXQgdGhlIGRhdGEgZm9yIEtpbmRsZSBhbmQgZmlsdGVyIG91dCB0aGUgd29yZHMuDQpraW5kbGUgPC0gZHBseXI6OmZpbHRlcihzb3J0ZWRfZGF0YV9mZWJfYXByXzIwMTksIGdyZXBsKCJLaW5kbGV8a2luZGxlfEUtcmVhZGVyIiwgbmFtZSkpDQpraW5kbGUkY2F0ZWdvcnkgPC0gIktpbmRsZSINCmtpbmRsZSRuYW1lIDwtIHN0cl9yZXBsYWNlX2FsbChraW5kbGUkbmFtZSwgY29tbW9uX2ZsdWZmX3N0cmluZywiIikNCmtpbmRsZSRuYW1lIDwtIHN0cl9yZXBsYWNlX2FsbChraW5kbGUkbmFtZSwgIkhpZ2gtUmVzb2x1dGlvbiBEaXNwbGF5fCgzMDAgcHBpKXxXaS1GaXxGcmVlIENlbGx1bGFyIENvbm5lY3Rpdml0eXwgYW5kIFBvd2VyIEFkYXB0ZXIgZm9yIEZpcmUgVGFibGV0cyBhbmQgS2luZGxlIGVSZWFkZXJzfFBvd2VyIEFkYXB0ZXIgV2FsbCBDaGFyZ2VyIEFuZCBVc2IgQ2FibGUgTWljcm8gVXNiIENvcmR8UGFnZVByZXNzIFNlbnNvcnMsIEZyZWUgM0ciLCAiIikNCmtpbmRsZSRuYW1lIDwtIHN0cl9yZXBsYWNlX2FsbChraW5kbGUkbmFtZSwgIihGaXRzIExhdGVzdCBHZW5lcmF0aW9uIEtpbmRsZSBhbmQgS2luZGxlIERYKXwgRm9yIHNoaXBtZW50IGluIHRoZSBVLlMgb25seXxJbnRlcm5hdGlvbmFsIENoYXJnaW5nIEtpdHwoZm9yIGFjY2VsZXJhdGVkIGNoYXJnaW5nIGluIG92ZXIgMjAwIGNvdW50cmllcyl8V2FsbCBUcmF2ZWwgQ2hhcmdlciBGaXJlfG1pY3JvIFVzYiBDYWJsZXxHbGFyZS1GcmVlIFRvdWNoc2NyZWVuIERpc3BsYXl8KCkiLCAiIikNCg0KIyBGaWx0ZXIgdW53YW50ZWQgd29yZHMgb3V0IG9mIEFtYXpvbiBFY2hvIHByb2R1Y3QuDQplY2hvIDwtIGRwbHlyOjpmaWx0ZXIoc29ydGVkX2RhdGFfZmViX2Fwcl8yMDE5LCBncmVwbCgiRWNob3xTbWFydCBBc3Npc3RhbnR8ZWNobyIsIG5hbWUpKQ0KZWNobyRjYXRlZ29yeSA8LSAiRWNobyINCnBvd2VyX2FkYXB0ZXIgPC0gZHBseXI6OmZpbHRlcihzb3J0ZWRfZGF0YV9mZWJfYXByXzIwMTksIGdyZXBsKCJQb3dlcnxDaGFyZ2VyfHBvd2VyIiwgbmFtZSkpDQpwb3dlcl9hZGFwdGVyJGNhdGVnb3J5IDwtICJwb3dlcl9hZGFwdGVyIg0KcG93ZXJfYWRhcHRlciRuYW1lIDwtIHN0cl9yZXBsYWNlX2FsbChwb3dlcl9hZGFwdGVyJG5hbWUsIGNvbW1vbl9mbHVmZl9zdHJpbmcsICIiKQ0KYGBgDQpPYnNlcnZhdGlvbiAxOg0KDQpOb3cgdGhhdCB3ZSBoYXZlIDUgdG9wIGRhdGFzZXRzIGlzb2xhdGVkIGJhc2VkIG9uIHRoZSBjYXRlZ29yeSwgbGV0IHVzIHBsb3QgdGhlIG51bWJlciBvZiByZXZpZXdzIGZvciBlYWNoIGNhdGVnb3J5LiBJbiB0aGlzIGdyYXBoLCBpdCBpcyBjbGVhcmx5IGV2aWRlbnQgdGhhdCBvbmUgb2YgdGhlIG1vc3QgcG9wdWxhciBhbWF6b24gaXRlbSBpcyB0aGUgYmF0dGVyaWVzIHRoYXQgQW1hem9uIHByb3ZpZGVzIGFzIGEgcGFydCBvZiBBbWF6b25CYXNpY3MgY2F0ZWdvcnkgbGluZS4gVGhpcyBpcyBub3QgdW51c3VhbCBzaW5jZSBBbWF6b25CYXNpY3MgYmF0dGVyaWVzIGFyZSBzb21lIG9mIHRoZSBiZXN0IHdoZW4gd2UgY29tcGFyZSBpdCB3aXRoIGNvbXBldGluZyBwcm9kdWN0cyBpbiBzaW1pbGFyIHByaWNlIHJhbmdlLiBGaXJlIFRhYmxldHMgaXMgYWxzbyBxdWl0ZSBwb3B1bGFyIGluIHJldmlld3MuIEFtYXpvbiBlY2hvIGlzIG5vdCBxdWl0ZSBwb3B1bGFyIGJ1dCB0aGlzIGNhbiBiZSBhdHRyaWJ1dGVkIHRvIHRoZSB0aW1lIG9mIGRhdGEgc2V0IHNpbmNlIFZvaWNlIEF1dG9tYXRpb24gd2Fzbid0IHByZXZhbGVudCBiYWNrIHRoZW4uIEtpbmRsZSBpcyBhbm90aGVyIGRlY2VudCBwcm9kdWN0IHdoaWNoIGhhcyBmYWlybHkgaGlnaCBudW1iZXIgb2YgcmF0aW5ncyB0b28uDQoNCmBgYHtyfQ0KIyBTZXQgdGhlIGFwcHJvcHJpYXRlIHRoZW1lcyBmb3IgdGhlIHBsb3QuDQpsaWJyYXJ5KGdncGxvdDIpDQp0aGVtZV9zZXQoDQogIHRoZW1lX21pbmltYWwoKSArDQogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImNlbnRlciIpDQogICkNCmxpYnJhcnkoUkNvbG9yQnJld2VyKQ0KDQojIFBsb3QgdGhlIHRvcCByZXZpZXdlZCBpdGVtcyBhbG9uZyB3aXRoIHRoZWlyIGNhdGVnb3J5LiBDYXRlZ29yeSBuYW1lcyBhcmUgdG9vIGJpZyB0byBiZSBkaXNwbGF5ZWQgaW4gdGhlIHNhbWUgY2hhcnQuDQojIEluIG9yZGVyIHRvIGdldCBhIHN0YWNrZWQgYmFyIHBsb3QsIHRoZSBmb2xsb3dpbmcgcmVmZXJlbmNlIHdhcyB1c2VkIHRvIGdldCB0aGUgaWRlYSAtIGh0dHA6Ly9yc3R1ZGlvLXB1YnMtc3RhdGljLnMzLmFtYXpvbmF3cy5jb20vMzI1Nl9iYjEwZGIxNDQwNzI0ZGFjOGZhNDBkYTVlNjU4YWRhNS5odG1sDQp0YWJsZV93aXRoX2luZGl2aWR1YWxfY2F0ZWdvcmllcyA8LSByYmluZChiYXR0ZXJpZXMsIGZpcmUsIGtpbmRsZSwgZWNobywgcG93ZXJfYWRhcHRlcikNCnRvcF9yZXZpZXdlZF9kYXRhX3Bsb3QgPC0gZ2dwbG90KGRhdGEgPSB0YWJsZV93aXRoX2luZGl2aWR1YWxfY2F0ZWdvcmllcywgYWVzKHggPSB0YWJsZV93aXRoX2luZGl2aWR1YWxfY2F0ZWdvcmllcyRjYXRlZ29yeSwgeSA9IG4sZmlsbD10YWJsZV93aXRoX2luZGl2aWR1YWxfY2F0ZWdvcmllcyRjYXRlZ29yeSkpICsgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiKQ0KdG9wX3Jldmlld2VkX2RhdGFfcGxvdCAgKyBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIkJsdWVzIikNCg0KDQpgYGANCk9ic2VydmF0aW9uIDI6DQoNCkluIG9yZGVyIHRvIGFuYWx5emUgY2xvc2VseSBpZiBjZXJ0YWluIHN1Yi1jYXRlZ29yaWVzIGhhcyBhbiBpbXBhY3QgaW4gdGhlIG92ZXJhbGwgYmFycGxvdCwgd2UgY29uc2lkZXIgdHdvIGNhdGVnb3JpZXMgZnJvbSB0aGUgYWJvdmUoRmlyZSBUYWJsZXRzIGFuZCBLaW5kbGUpIGFuZCBhbmFseXplIHRoZSBwZXJjZW50YWdlIGNvbXBvc2l0aW9uIG9mIHN1Yi1jYXRlZ29yaWVzIGJhc2VkIG9uIHRoZSBuYW1lIHByb3ZpZGVkLiBBIGxvdCBvZiBzZWxsZXJzIHByb3ZpZGUgZGV0YWlsZWQgZGVzY3JpcHRpb24gd2l0aGluIHRoZSBuYW1lIHdoaWNoIGFjdHMgYXMgYSBwcm9wZWxsYW50IGZvciBjZXJ0YWluIGl0ZW1zIHRvIGJlIHNvbGQgbW9yZSB0aGFuIHRoZSByZXN0LiBGb3IgZXhhbXBsZSBpbiBGaXJlIHRhYmxldCBzYWxlLCB0aGUgbW9zdCBwb3B1bGFyIGl0ZW0gc2VlbXMgdG8gYmUgdGhlIDE2R0IgdGFibGV0IGZvbGxvd2VkIGNsb3NlbHkgYnkgdGFibGV0cyBzcGVjaWZpYyBmb3IgS2lkcyAoRmlyZSBLaWRzKS4gVGhpcyBwcm92aWRlcyBhIGhpbnQgdGhhdCBhIGxvdCBvZiBjb25zdW1lcnMgYnV5IEZpcmUgdGFibGV0cyBmb3IgdGhlaXIga2lkcyBhbmQgYWxzbyBidXkgaXQgd2l0aCBtaW5pbWFsIGNvbmZpZyAoMTZHQikgY29tcGFyZWQgdG8gdGhlIG1heGltdW0gY29uZmlndXJhdGlvbiBwcm92aWRlZCgzMkcpLg0KDQpgYGB7cn0NCg0KIyBDYWxjdWxhdGUgdGhlIHBlcmNlbnRhZ2Ugb2YgZWFjaCBuYW1lIGJhc2VkIG9uIHRoZSB0b3AgZmV3IHJvd3MNCnRvcF8xMF9maXJlX3RhYmxldF9yZXZpZXdzID0gaGVhZChmaXJlLCAxMCkNCnRvcF8xMF9maXJlX3RhYmxldF9yZXZpZXdzJHBlcmNlbnRhZ2UgPC0gKHRvcF8xMF9maXJlX3RhYmxldF9yZXZpZXdzJG4gLyBzdW0odG9wXzEwX2ZpcmVfdGFibGV0X3Jldmlld3MkbikgKiAxMDAuMCkNCnRvcF8xMF9maXJlX3RhYmxldF9yZXZpZXdzDQoNCiMgQ3JlYXRlIGEgcGllIGNoYXJ0IHdpdGggdGhlIHRvcCAxMCBmaXJlIHRhYmxldCByZXZpZXdzLiBGb3JtYXQvY29sb3Igb2YgdGhlIHBpZSBjaGFydCBmcm9tIGh0dHBzOi8vd3d3LnItYmxvZ2dlcnMuY29tL2hvdy10by1tYWtlLWEtcGllLWNoYXJ0LWluLXIvDQpwaWVfZmlyZV90YWJsZXQgPSBnZ3Bsb3QodG9wXzEwX2ZpcmVfdGFibGV0X3Jldmlld3MsIGFlcyh4PSIiLCB5PXBlcmNlbnRhZ2UsIGZpbGw9bmFtZSkpICsgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCB3aWR0aD0xKSArIGNvb3JkX3BvbGFyKCJ5Iiwgc3RhcnQ9MCkgKyBnZW9tX3RleHQoYWVzKGxhYmVsID0gcGFzdGUwKHJvdW5kKHBlcmNlbnRhZ2UpLCAiJSIpKSwgcG9zaXRpb24gPSBwb3NpdGlvbl9zdGFjayh2anVzdCA9IDAuNSkpICsgbGFicyh4ID0gTlVMTCwgeSA9IE5VTEwsIGZpbGwgPSBOVUxMLCB0aXRsZSA9ICJGaXJlIFRhYmxldHMiKSArIHRoZW1lX2NsYXNzaWMoKSArIHRoZW1lKGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBjb2xvciA9ICIjNjY2NjY2IikpDQpwaWVfZmlyZV90YWJsZXQNCmBgYA0KT2JzZXJ2YXRpb24gMzoNCg0KU2ltaWxhcmx5IGZvciBLaW5kbGUgcHJvZHVjdCwgS2luZGxlIFZveWFnZSBzZWVtcyB0byBiZSB0aGUgbW9zdCBwb3B1bGFyIGluIHRoaXMgdGltZSBmcmFtZSBmb2xsb3dlZCBieSB0aGUgS2luZGxlIHZlcnNpb24gd2hpY2ggY29tZXMgaW4gd2hpdGUuIFNlbGxlcnMgd2hvIHNlbGwga2luZGxlIGFsb25nIHdpdGggYSBjb3ZlciAoTGVhdGhlciBDaGFyZ2luZyBDb3Zlcikgc2VlbSB0byBiZW5lZml0IGFzIHdlbGwuDQoNCmBgYHtyfQ0KIyBOb3cgbGV0J3MgZG8gdGhlIHNhbWUgZm9yIGtpbmRsZSAtIENvbXB1dGluZyB0aGUgY29tcG9zaXRpb24gb2YgcmV2aWV3ZXMgZm9yIGtpbmRsZSBwcm9kdWN0Lg0Ka2luZGxlJHBlcmNlbnRhZ2UgPC0ga2luZGxlJG4gLyBzdW0oa2luZGxlJG4pICogMTAwDQpraW5kbGUNCnBpZV9raW5kbGUgPSBnZ3Bsb3Qoa2luZGxlLCBhZXMoeD0iIiwgeT1wZXJjZW50YWdlLCBmaWxsPW5hbWUpKSArIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5Iiwgd2lkdGg9MSkgKyBjb29yZF9wb2xhcigieSIsIHN0YXJ0PTApICsgbGFicyh4ID0gTlVMTCwgeSA9IE5VTEwsIGZpbGwgPSBOVUxMLCB0aXRsZSA9ICJLaW5kbGUiKSArIHRoZW1lX2NsYXNzaWMoKSArIHRoZW1lKGF4aXMubGluZSA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBheGlzLnRleHQgPSBlbGVtZW50X2JsYW5rKCksDQogICAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwNCiAgICAgICAgICBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41LCBjb2xvciA9ICIjNzc3Nzc3IikpDQpwaWVfa2luZGxlDQoNCmBgYA0KT2JzZXJ2YXRpb24gNDoNCg0KTGV0IHVzIGFuYWx5emUgQW1hem9uQmFzaWNzIGJhdHRlcmllcyB3aGljaCBzZWVtIHRvIGJlIHF1aXRlIHBvcHVsYXIgd2l0aCBjb25zdW1lcnMuIFRoZXJlIGFyZSB0d28gY2F0ZWdvcmllcyBzb2xkIChBQSBhbmQgQUFBKSBhbmQgYm90aCBvZiB0aGVtIGFyZSBoaWdoIHNlbGxlcnMuIFdlIGFyZSBnb2luZyB0byBjaGVjayB3aGV0aGVyIHRoZSByYXRpbmdzIGZvciBiYXR0ZXJpZXMgdmFyaWVzIGFjY29yZGluZyB0byB0aGUgdGltZSBvZiB0aGUgeWVhci4gVGhpcyBpcyBiYXNlZCBvbiB0aGUgY29sdW1uIHdoaWNoIGhhcyB0aGUgZGF0ZSB3aGVuIHRoZSBwcm9kdWN0IHdhcyByZXZpZXdlZC4gT25lIGFzc3VtcHRpb24gdGhhdCB3ZSBtYWtlIGhlcmUgaXMgdGhhdCBhIGN1c3RvbWVyIHdobyBidXlzIGEgcHJvZHVjdCBmcm9tIEFtYXpvbiBpcyBsaWtlbHkgdG8gcmVjZWl2ZSBhbiBlbWFpbCB0byBzdWJtaXQgYSByZXZpZXcgd2l0aGluIHRoZSBmaXJzdCBmZXcgd2Vla3MgYW5kIHN1Ym1pdCBvbmUgc2hvcnRseSBhZnRlciByZWNlaXZpbmcgaXQuIEZyb20gdGhlIHBsb3RzLCB3ZSBjYW4gc2VlIHR3byBvYnNlcnZhdGlvbnMNCg0KMS4gVGhpcyBwcm9kdWN0IHRvb2sgYSBsaXR0bGUgdGltZSB0byBiZSBwb3B1bGFyIG93aW5nIHRvIHRoZSBsYWNrIG9mIHJldmlld3MgaW5pdGlhbGx5Lg0KMi4gVGhlIHByb2R1Y3QgaXMgcXVpdGUgcG9wdWxhciBkdXJpbmcgdGhlIGhvbGlkYXlzLg0KDQpgYGB7cn0NCiMgTm93IGZvciB0aGUgdG9wIHJhdGVkIGl0ZW0sIEFtYXpvbkJhc2ljcyBiYXR0ZXJpZXMsIGxldCB1cyBjaGVjayB0aGUgcmV2aWV3IHJhdGUgYW5kIHNlZSBpZiB0aGUgcmV2aWV3cyBhcmUgZGlzdHJpYnV0ZWQgb3ZlciB0aW1lDQphbGxfYmF0dGVyeV9yZXZpZXdzIDwtIGRwbHlyOjpmaWx0ZXIoYW1hem9uX3Jldmlld19kYXRhX2ZlYl9hcHJfMjAxOSwgZ3JlcGwoIlBlcmZvcm1hbmNlIEFsa2FsaW5lIEJhdHRlcmllcyIsbmFtZSkpDQoNCiMgV2UgYXJlIG9ubHkgY29uY2VybmVkIHdpdGggcmV2aWV3IGRhdGUgYW5kIHJhdGluZ3MgZm9yIHRoZXNlIHByb2R1Y3RzDQojIFRvIGdyb3VwIHRoZSByZXZpZXdzIG9uIGEgbW9udGhseSBiYXNpcywgbGV0J3MgY2xlYW4gdGhlIHRpbWVzdGFtcCBiZWZvcmUgZ3JvdXBpbmcgdGhlbQ0KaW5zdGFsbC5wYWNrYWdlcygibHVicmlkYXRlIikNCmxpYnJhcnkobHVicmlkYXRlKQ0KYWxsX2JhdHRlcnlfcmV2aWV3cyAlPiUgc2VsZWN0KG5hbWUsIHJldmlld3MuZGF0ZSkgLT4gYmF0dGVyeV9yZXZpZXdfZGF0ZQ0KYmF0dGVyeV9yZXZpZXdfZGF0ZSRyZXZpZXdzLmRhdGUgPC0gYXMuRGF0ZShiYXR0ZXJ5X3Jldmlld19kYXRlJHJldmlld3MuZGF0ZSkNCmJhdHRlcnlfcmV2aWV3X2RhdGUgJT4lIGFycmFuZ2UocmV2aWV3cy5kYXRlKSAtPiBzb3J0ZWRfYmF0dGVyeV9yZXZpZXdfZGF0ZQ0KDQojIEZvciBlYWNoIHJldmlldywgbGV0IHVzIGFkZCBhIGNvbHVtbiB0byBpbmRpY2F0ZSB0aGUgY291bnQgb2YgcmV2aWV3LiBBcyB3ZSBncm91cCB0aGUgcmV2aWV3cyBiYXNlZCBvbiBtb250aCBhbmQgeWVhciwgdGhlc2Ugd2lsbCBiZSBhY2N1bXVsYXRlZA0Kc29ydGVkX2JhdHRlcnlfcmV2aWV3X2RhdGUkbnVtX3Jldmlld3MgPC0gMQ0KDQojIEdyb3VwIHRoZSByZXZpZXdzIGJhc2VkIG9uIHRpbWVyYW5nZSAtIHNvdXJjZTogaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMzMyMjE0MjUvaG93LWRvLWktZ3JvdXAtbXktZGF0ZS12YXJpYWJsZS1pbnRvLW1vbnRoLXllYXItaW4tci8zMzIyMTg4NQ0Kc29ydGVkX2JhdHRlcnlfcmV2aWV3X2RhdGUgJT4lIG11dGF0ZShtb250aCA9IGZvcm1hdChyZXZpZXdzLmRhdGUsICIlbSIpLCB5ZWFyID0gZm9ybWF0KHJldmlld3MuZGF0ZSwgIiVZIikpICU+JQ0KZ3JvdXBfYnkobW9udGgsIHllYXIpIC0+IGJhdHRlcnlfcmV2aWV3c19pbl9vcmRlcg0KDQojIFNpbmNlIHdlIGdyb3VwZWQgdGhlIHJldmlldyBjb3VudCwgdGhlIHNvcnRlZCBkYXRhIGlzIG5vdyB1bnNvcnRlZC4gTGV0J3Mgc29ydCB0aGVtIHRvIGRpc3BsYXkgdGhlIHRpbWVsaW5lLiBTaW5jZSB3ZSBhcmUgZm9jdXNlZCBvbiB0aGUgbW9udGgsIHdlIHdpbGwgdHJlYXQgdGhlIDFzdCBvZiBlYWNoIG1vbnRoIGluIG91ciBjYWxjdWxhdGlvbiBiYXNlZCBvbiB0aGUgbW9udGggYW5kIHRoZSB5ZWFyIHRoZSByZXZpZXcgaXMgc2V0Lg0KYmF0dGVyeV9yZXZpZXdzX2luX29yZGVyICU+JSBzdW1tYXJpc2UobnVtX3Jldmlld3M9c3VtKG51bV9yZXZpZXdzKSkgLT4gYmF0dGVyeV9yZXZpZXdzX3Blcl9tb250aA0KYmF0dGVyeV9yZXZpZXdzX3Blcl9tb250aCREYXRlIDwtIHBhc3RlKGJhdHRlcnlfcmV2aWV3c19wZXJfbW9udGgkeWVhciwgYmF0dGVyeV9yZXZpZXdzX3Blcl9tb250aCRtb250aCwgIjAxIiwgc2VwPSItIikNCmJhdHRlcnlfcmV2aWV3c19wZXJfbW9udGgkRGF0ZSA8LSBhcy5EYXRlKGJhdHRlcnlfcmV2aWV3c19wZXJfbW9udGgkRGF0ZSwgIiVZLSVtLSVkIikNCmJhdHRlcnlfcmV2aWV3c19wZXJfbW9udGggJT4lIGFycmFuZ2UoRGF0ZSkgLT4gc29ydGVkX2JhdHRlcnlfcmV2aWV3c19iYXNlZF9vbl9kYXRlDQpzb3J0ZWRfYmF0dGVyeV9yZXZpZXdzX2Jhc2VkX29uX2RhdGUkYWN0aXZpdHkgPC0NCiAgaWZlbHNlKHNvcnRlZF9iYXR0ZXJ5X3Jldmlld3NfYmFzZWRfb25fZGF0ZSRudW1fcmV2aWV3cyA8IDQwLCAiTG93IiwNCiAgICAgICAgIGlmZWxzZShzb3J0ZWRfYmF0dGVyeV9yZXZpZXdzX2Jhc2VkX29uX2RhdGUkbnVtX3Jldmlld3MgPiA0MCAmDQogICAgICAgICAgICAgICAgc29ydGVkX2JhdHRlcnlfcmV2aWV3c19iYXNlZF9vbl9kYXRlJG51bV9yZXZpZXdzIDwgMjAwLCAiTWlkIiwNCiAgICAgICAgIGlmZWxzZShzb3J0ZWRfYmF0dGVyeV9yZXZpZXdzX2Jhc2VkX29uX2RhdGUkbnVtX3Jldmlld3MgPiAyMDAgJg0KICAgICAgICAgICAgICAgIHNvcnRlZF9iYXR0ZXJ5X3Jldmlld3NfYmFzZWRfb25fZGF0ZSRudW1fcmV2aWV3cyA8IDM1MCAsICJIaWdoIiwNCiAgICAgICAgIGlmZWxzZShzb3J0ZWRfYmF0dGVyeV9yZXZpZXdzX2Jhc2VkX29uX2RhdGUkbnVtX3Jldmlld3MgPCAxMDAwLCAiVmVyeV9IaWdoIiwiIikpKSkNCg0KIyBQbG90dGluZyBhIHRpbWVsaW5lIHdhcyByZWZlcmVuY2VkIHVzaW5nIGh0dHA6Ly9iZW5hbGV4a2Vlbi5jb20vY3JlYXRpbmctYS10aW1lbGluZS1ncmFwaGljLXVzaW5nLXItYW5kLWdncGxvdDIvIHdoaWNoIHVzZWQgcHJvamVjdCB0aW1lbGluZXMuIFdlIHVzZSBzaW1pbGFyIHN0cmF0ZWd5IHRvIGNvbXBhcmUgdGhlIG51bWViciBvZiByZXZpZXdzIHRoYXQgd2FzIHJlY29yZGVkIHBlciBtb250aC4NCnJldmlld19sZXZlbHMgPC0gYygiTG93IiwgIk1pZCIsICJIaWdoIiwgIlZlcnlfSGlnaCIpDQpzdGF0dXNfY29sb3JzIDwtIGMoIiMwMDcwQzAiLCAiIzAwQjA1MCIsICIjRkZDMDAwIiwgIiNDMDAwMDAiKQ0Kc29ydGVkX2JhdHRlcnlfcmV2aWV3c19iYXNlZF9vbl9kYXRlJGFjdGl2aXR5IDwtIGZhY3Rvcihzb3J0ZWRfYmF0dGVyeV9yZXZpZXdzX2Jhc2VkX29uX2RhdGUkYWN0aXZpdHksIGxldmVscz1yZXZpZXdfbGV2ZWxzKQ0Kc29ydGVkX2JhdHRlcnlfcmV2aWV3c19iYXNlZF9vbl9kYXRlDQoNCiMgVmFyaWFiaWxpdHkgb2YgcmV2aWV3cyBvbiBhIHBsb3Qgc2hvd3MgdGhhdCB0aGUgcHJvZHVjdCBpcyBxdWl0ZSBwb3B1bGFyIGR1cmluZyB0aGUgaG9saWRheXMuDQppbnN0YWxsLnBhY2thZ2VzKCJocmJydGhlbWVzIikNCmJhdHRlcnlfcGxvdCA8LSBnZ3Bsb3QoZGF0YSA9IHNvcnRlZF9iYXR0ZXJ5X3Jldmlld3NfYmFzZWRfb25fZGF0ZSwgYWVzKHggPSBzb3J0ZWRfYmF0dGVyeV9yZXZpZXdzX2Jhc2VkX29uX2RhdGUkRGF0ZSwgeSA9IHNvcnRlZF9iYXR0ZXJ5X3Jldmlld3NfYmFzZWRfb25fZGF0ZSRudW1fcmV2aWV3cykpICsgZ2VvbV9wb2ludChzdGF0PSJpZGVudGl0eSIpICsgZ2VvbV9saW5lKGNvbG9yPSIjZTllY2VmIikrIGdndGl0bGUoIkFtYXpvbkJhc2ljcyBCYXR0ZXJpZXMiLCBzdWJ0aXRsZT0iUmV2aWV3IHJhdGUgb3ZlciB0aW1lIikgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKyB0aGVtZShwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCmJhdHRlcnlfcGxvdA0KYGBgDQpPYnNlcnZhdGlvbiA1Og0KDQpTaW1pbGFybHksIGZvciBGaXJlIFRhYmxldHMsIGlmIHdlIHBsb3QgdGhlIHJldmlld3MgYWNjb3JkaW5nIHRvIHRoZSB0aW1lbGluZSwgd2UgY2FuIHNlZSB0aGF0IHRoZSB0YWJsZXRzIGFyZSB2ZXJ5IHBvcHVsYXIgZHVyaW5nIHRoZSBob2xpZGF5cy4gVGhlc2UgdGFibGV0cyBhcmUgcXVpdGUgcG9wdWxhciBwcmltYXJpbHkgYmVjYXVzZSBvZiB0aGVpciBwcmljZSBwb2ludCAocmVsYXRpdmVseSBjaGVhcCBjb21wYXJlZCB0byBpdHMgbWFpbiBjb21wZXRpdG9yLSBBcHBsZSBJcGFkKSBhbmQgdGhlIHRhcmdldCBkZW1vZ3JhcGhpYyBmb3IgdGhlc2UgdGFibGV0cywgd2hpY2ggaXMgZm9jdXNzZWQgdG93YXJkcyBraWRzIGR1cmluZyB0aGUgaG9saWRheXMgYXMgYSBnaWZ0IChiYXNlZCBvbiB0aGUgZWFybGllciBwaWUgY2hhcnQpLiANCg0KYGBge3J9DQojIE5vdyBkbyB0aGUgc2FtZSBmb3IgRmlyZSBUYWJsZXRzDQphbGxfZmlyZV9yZXZpZXdzIDwtIGRwbHlyOjpmaWx0ZXIoYW1hem9uX3Jldmlld19kYXRhX2ZlYl9hcHJfMjAxOSwgZ3JlcGwoIkZpcmV8ZmlyZSIsIG5hbWUpKQ0KYWxsX2ZpcmVfcmV2aWV3cyAlPiUgc2VsZWN0KG5hbWUsIHJldmlld3MuZGF0ZSkgLT4gZmlyZV9yZXZpZXdfZGF0ZQ0KZmlyZV9yZXZpZXdfZGF0ZSRyZXZpZXdzLmRhdGUgPC0gYXMuRGF0ZShmaXJlX3Jldmlld19kYXRlJHJldmlld3MuZGF0ZSkNCmZpcmVfcmV2aWV3X2RhdGUgJT4lIGFycmFuZ2UocmV2aWV3cy5kYXRlKSAtPiBzb3J0ZWRfZmlyZV9yZXZpZXdfZGF0ZQ0KDQojIEZvciBlYWNoIHJldmlldywgbGV0IHVzIGFkZCBhIGNvbHVtbiB0byBpbmRpY2F0ZSB0aGUgY291bnQgb2YgcmV2aWV3LiBBcyB3ZSBncm91cCB0aGUgcmV2aWV3cyBiYXNlZCBvbiBtb250aCBhbmQgeWVhciwgdGhlc2Ugd2lsbCBiZSBhY2N1bXVsYXRlZA0Kc29ydGVkX2ZpcmVfcmV2aWV3X2RhdGUkbnVtX3Jldmlld3MgPC0gMQ0KDQojIEdyb3VwIHRoZSByZXZpZXdzIGJhc2VkIG9uIHRpbWVsaW5lIC0gc291cmNlOiBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy8zMzIyMTQyNS9ob3ctZG8taS1ncm91cC1teS1kYXRlLXZhcmlhYmxlLWludG8tbW9udGgteWVhci1pbi1yLzMzMjIxODg1DQpzb3J0ZWRfZmlyZV9yZXZpZXdfZGF0ZSAlPiUgbXV0YXRlKG1vbnRoID0gZm9ybWF0KHJldmlld3MuZGF0ZSwgIiVtIiksIHllYXIgPSBmb3JtYXQocmV2aWV3cy5kYXRlLCAiJVkiKSkgJT4lDQpncm91cF9ieShtb250aCwgeWVhcikgLT4gZmlyZV9yZXZpZXdzX2luX29yZGVyDQoNCiMgU2luY2Ugd2UgZ3JvdXBlZCB0aGUgcmV2aWV3IGNvdW50LCB0aGUgc29ydGVkIGRhdGEgaXMgbm93IHVuc29ydGVkLiBMZXQncyBzb3J0IHRoZW0gdG8gZGlzcGxheSB0aGUgdGltZWxpbmUuIFNpbmNlIHdlIGFyZSBmb2N1c2VkIG9uIHRoZSBtb250aCwgd2Ugd2lsbCB0cmVhdCB0aGUgMXN0IG9mIGVhY2ggbW9udGggaW4gb3VyIGNhbGN1bGF0aW9uIGJhc2VkIG9uIHRoZSBtb250aCBhbmQgdGhlIHllYXIgdGhlIHJldmlldyBpcyBzZXQuDQpmaXJlX3Jldmlld3NfaW5fb3JkZXIgJT4lIHN1bW1hcmlzZShudW1fcmV2aWV3cz1zdW0obnVtX3Jldmlld3MpKSAtPiBmaXJlX3Jldmlld3NfcGVyX21vbnRoDQpmaXJlX3Jldmlld3NfcGVyX21vbnRoJERhdGUgPC0gcGFzdGUoZmlyZV9yZXZpZXdzX3Blcl9tb250aCR5ZWFyLCBmaXJlX3Jldmlld3NfcGVyX21vbnRoJG1vbnRoLCAiMDEiLCBzZXA9Ii0iKQ0KZmlyZV9yZXZpZXdzX3Blcl9tb250aCREYXRlIDwtIGFzLkRhdGUoZmlyZV9yZXZpZXdzX3Blcl9tb250aCREYXRlLCAiJVktJW0tJWQiKQ0KZmlyZV9yZXZpZXdzX3Blcl9tb250aCAlPiUgYXJyYW5nZShEYXRlKSAtPiBzb3J0ZWRfZmlyZV9yZXZpZXdzX3Blcl9tb250aA0Kc29ydGVkX2ZpcmVfcmV2aWV3c19wZXJfbW9udGgNCg0KIyBWYXJpYWJpbGl0eSBvZiByZXZpZXdzDQpmaXJlX3Bsb3QgPC0gZ2dwbG90KGRhdGEgPSBzb3J0ZWRfZmlyZV9yZXZpZXdzX3Blcl9tb250aCwgYWVzKHggPSBzb3J0ZWRfZmlyZV9yZXZpZXdzX3Blcl9tb250aCREYXRlLCB5ID0gc29ydGVkX2ZpcmVfcmV2aWV3c19wZXJfbW9udGgkbnVtX3Jldmlld3MpKSArIGdlb21fcG9pbnQoc3RhdD0iaWRlbnRpdHkiLCBjb2xvcj0ibmF2eWJsdWUiKSArIGdlb21fbGluZShjb2xvcj0iI2U5ZWNlZiIpKyBnZ3RpdGxlKCJGaXJlIFRhYmxldHMiLCBzdWJ0aXRsZT0iUmV2aWV3IHJhdGUgb3ZlciB0aW1lIikgKyB0aGVtZShwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkgKyB0aGVtZShwbG90LnN1YnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkNCmZpcmVfcGxvdA0KDQpgYGANCk9ic2VydmF0aW9uIDY6DQoNCkRhdGEgZm9yIEtpbmRsZSB0YWJsZXRzIGlzIG5vdCBhcyBwcmVkaWN0YWJsZSBhcyB0aGUgZWFybGllciBjYXRlZ29yaWVzIHNpbmNlIHRoZSByZXZpZXdzIGFyZSBzcHJlYWQgb3ZlciB0aGUgeWVhci4gS2luZGxlIGlzIGEgZ3JlYXQgcHJvZHVjdCBmb3IgRS1yZWFkZXJzIGFuZCB0aGUgdGFyZ2V0IGRlbW9ncmFwaGljIGlzIG5vdCBxdWl0ZSBuYXJyb3cuIEluIGFkZGl0aW9uIHRvIEtpbmRsZSBFLXJlYWRlcnMsIHRoaXMgZGF0YSBzZXQgYWxzbyBpbmNsdWRlcyBwb3dlci1hZGFwdGVycyBmb3IgS2luZGxlIHJlYWRlcnMgd2hpY2ggY291bGQgaGF2ZSBza2V3ZWQgdGhlIHJlc3VsdHMuIA0KDQpgYGB7cn0NCiMgU2ltaWxhciB3b3JrZmxvdyBmb3IgS2luZGxlIHByb2R1Y3QNCmFsbF9raW5kbGVfcmV2aWV3cyA8LSBkcGx5cjo6ZmlsdGVyKGFtYXpvbl9yZXZpZXdfZGF0YV9mZWJfYXByXzIwMTksIGdyZXBsKCJLaW5kbGV8a2luZGxlfEUtcmVhZGVyIiwgbmFtZSkpDQphbGxfa2luZGxlX3Jldmlld3MgJT4lIHNlbGVjdChuYW1lLCByZXZpZXdzLmRhdGUpIC0+IGtpbmRsZV9yZXZpZXdfZGF0ZQ0Ka2luZGxlX3Jldmlld19kYXRlJHJldmlld3MuZGF0ZSA8LSBhcy5EYXRlKGtpbmRsZV9yZXZpZXdfZGF0ZSRyZXZpZXdzLmRhdGUpDQpraW5kbGVfcmV2aWV3X2RhdGUgJT4lIGFycmFuZ2UocmV2aWV3cy5kYXRlKSAtPiBzb3J0ZWRfa2luZGxlX3Jldmlld19kYXRlDQoNCiMgRm9yIGVhY2ggcmV2aWV3LCBsZXQgdXMgYWRkIGEgY29sdW1uIHRvIGluZGljYXRlIHRoZSBjb3VudCBvZiByZXZpZXcuIEFzIHdlIGdyb3VwIHRoZSByZXZpZXdzIGJhc2VkIG9uIG1vbnRoIGFuZCB5ZWFyLCB0aGVzZSB3aWxsIGJlIGFjY3VtdWxhdGVkDQpzb3J0ZWRfa2luZGxlX3Jldmlld19kYXRlJG51bV9yZXZpZXdzIDwtIDENCg0KIyBHcm91cCB0aGUgcmV2aWV3cyBiYXNlZCBvbiB0aW1lbGluZSAtIHNvdXJjZTogaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xdWVzdGlvbnMvMzMyMjE0MjUvaG93LWRvLWktZ3JvdXAtbXktZGF0ZS12YXJpYWJsZS1pbnRvLW1vbnRoLXllYXItaW4tci8zMzIyMTg4NQ0Kc29ydGVkX2tpbmRsZV9yZXZpZXdfZGF0ZSAlPiUgbXV0YXRlKG1vbnRoID0gZm9ybWF0KHJldmlld3MuZGF0ZSwgIiVtIiksIHllYXIgPSBmb3JtYXQocmV2aWV3cy5kYXRlLCAiJVkiKSkgJT4lDQpncm91cF9ieShtb250aCwgeWVhcikgLT4ga2luZGxlX3Jldmlld3NfaW5fb3JkZXINCg0KIyBTaW5jZSB3ZSBncm91cGVkIHRoZSByZXZpZXcgY291bnQsIHRoZSBzb3J0ZWQgZGF0YSBpcyBub3cgdW5zb3J0ZWQuIExldCdzIHNvcnQgdGhlbSB0byBkaXNwbGF5IHRoZSB0aW1lbGluZS4gU2luY2Ugd2UgYXJlIGZvY3VzZWQgb24gdGhlIG1vbnRoLCB3ZSB3aWxsIHRyZWF0IHRoZSAxc3Qgb2YgZWFjaCBtb250aCBpbiBvdXIgY2FsY3VsYXRpb24gYmFzZWQgb24gdGhlIG1vbnRoIGFuZCB0aGUgeWVhciB0aGUgcmV2aWV3IGlzIHNldC4NCmtpbmRsZV9yZXZpZXdzX2luX29yZGVyICU+JSBzdW1tYXJpc2UobnVtX3Jldmlld3M9c3VtKG51bV9yZXZpZXdzKSkgLT4ga2luZGxlX3Jldmlld3NfcGVyX21vbnRoDQpraW5kbGVfcmV2aWV3c19wZXJfbW9udGgkRGF0ZSA8LSBwYXN0ZShraW5kbGVfcmV2aWV3c19wZXJfbW9udGgkeWVhciwga2luZGxlX3Jldmlld3NfcGVyX21vbnRoJG1vbnRoLCAiMDEiLCBzZXA9Ii0iKQ0Ka2luZGxlX3Jldmlld3NfcGVyX21vbnRoJERhdGUgPC0gYXMuRGF0ZShraW5kbGVfcmV2aWV3c19wZXJfbW9udGgkRGF0ZSwgIiVZLSVtLSVkIikNCmtpbmRsZV9yZXZpZXdzX3Blcl9tb250aCAlPiUgYXJyYW5nZShEYXRlKSAtPiBzb3J0ZWRfa2luZGxlX3Jldmlld3NfcGVyX21vbnRoDQpzb3J0ZWRfa2luZGxlX3Jldmlld3NfcGVyX21vbnRoDQoNCiMgVmFyaWFiaWxpdHkgb2YgcmV2aWV3cw0Ka2luZGxlX3Bsb3QgPC0gZ2dwbG90KGRhdGEgPSBzb3J0ZWRfa2luZGxlX3Jldmlld3NfcGVyX21vbnRoLCBhZXMoeCA9IHNvcnRlZF9raW5kbGVfcmV2aWV3c19wZXJfbW9udGgkRGF0ZSwgeSA9IHNvcnRlZF9raW5kbGVfcmV2aWV3c19wZXJfbW9udGgkbnVtX3Jldmlld3MpKSArIGdlb21fcG9pbnQoc3RhdD0iaWRlbnRpdHkiLCBjb2xvcj0ic3ByaW5nZ3JlZW4zIikgKyBnZW9tX2xpbmUoY29sb3I9IiNlOWVjZWYiKSsgZ2d0aXRsZSgiQW1hem9uIEtpbmRsZSIsIHN1YnRpdGxlPSJSZXZpZXcgcmF0ZSBvdmVyIHRpbWUiKSArIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKSArIHRoZW1lKHBsb3Quc3VidGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQ0Ka2luZGxlX3Bsb3QNCmBgYA0KT2JzZXJ2YXRpb24gNzoNCg0KTm93IGxldCB1cyBjb21wYXJlIHRoZSByYXRpbmdzIGZvciBlYWNoIG9mIHRoZXNlIGNhdGVnb3JpZXMgYW5kIHBsb3QgdmFyaWFiaWxpdHkgaW4gd2hpY2ggdXNlcnMgYXJlIGxpa2VseSB0byBwcm92aWRlIGEgYmV0dGVyIHJhdGluZyBmb3IgY2VydGFpbiBwcm9kdWN0LiBCYXNlZCBvbiB0aGUgZmlsdGVyZWQgZGF0YSBzZXQsIEZpcmUgVGFibGV0cyBoYXZlIHF1aXRlIGEgbGFyZ2UgbnVtYmVyIG9mICI0IiByYXRpbmdzIHdoaWxlIEtpbmRsZSBhbmQgYmF0dGVyaWVzIGhhdmUgaGlnaCBudW1iZXIgb2YgY29uc3VtZXJzIGdpdmluZyBpdCAiNSIgb3V0IG9mICI1Ii4gVGhlIHVzYWJpbGl0eSBvZiBGaXJlIHRhYmxldHMgY291bGQgYmUgb25lIG9mIHRoZSByZWFzb24gZm9yIHRoaXMgb2JzZXJ2YXRpb24uIA0KT25lIG90aGVyIG9ic2VydmF0aW9uIHRoYXQgd2FzIGZvdW5kIGhlcmUgaXMgdGhhdCBiYXR0ZXJpZXMgaGF2ZSBtb3JlIG51bWJlciBvZiB1bnNhdGlzZmllZCBjdXN0b21lcnMgd2hvIHByb3ZpZGVkICIxIi4gSWYgd2UgYW5hbHl6ZSBzb21lIG9mIHRoZXNlIHJhdGluZ3MsIGEgbG90IG9mIGl0IGlzIGR1ZSB0byB0aGUgZGVmZWN0aXZlIHByb2R1Y3QgdGhhdCBnZXRzIHNoaXBwZWQgYW5kIGFsc28gdGhlIGxpZmV0aW1lIG9mIGEgYmF0dGVyeS4gV2hpbGUgQW1hem9uIGlzIGxpa2VseSB0byBhY2NlcHQgc3VjaCBpdGVtcyBhcyBSZXR1cm5zIGFuZCBwcm92aWRlIGEgbmV3IG9uZSwgYSBjdXN0b21lciBpcyB1bmxpa2VseSB0byBzdWJtaXQvZWRpdCBoaXMgYWxyZWFkeSBjb21wbGV0ZWQgcmV2aWV3LiANCg0KYGBge3J9DQojIENvbXBhcmluZyByZXZpZXcgcmF0aW5ncyBvZiB2YXJpb3VzIHByb2R1Y3QgY2F0ZWdvcmllcy4NCmFsbF9maXJlX3Jldmlld3MgJT4lIHNlbGVjdChuYW1lLCByZXZpZXdzLnJhdGluZykgLT4gYWxsX2ZpcmVfcmV2aWV3c19yYXRpbmdzDQphbGxfa2luZGxlX3Jldmlld3MgJT4lIHNlbGVjdChuYW1lLCByZXZpZXdzLnJhdGluZykgLT4gYWxsX2tpbmRsZV9yZXZpZXdzX3JhdGluZ3MNCmFsbF9iYXR0ZXJ5X3Jldmlld3MgJT4lIHNlbGVjdChuYW1lLCByZXZpZXdzLnJhdGluZykgLT4gYWxsX2JhdHRlcnlfcmV2aWV3c19yYXRpbmdzDQoNCiMgTm93IHBsb3QgYSBkZW5zaXR5IGdyYXBoIHdpdGggZWFjaCBjYXRlZ29yeS4NCmFsbF9maXJlX3Jldmlld3NfcmF0aW5ncyRJdGVtID0gIkFtYXpvbiBGaXJlIg0KYWxsX2tpbmRsZV9yZXZpZXdzX3JhdGluZ3MkSXRlbSA9ICJBbWF6b24gS2luZGxlIg0KYWxsX2JhdHRlcnlfcmV2aWV3c19yYXRpbmdzJEl0ZW0gPSAiQW1hem9uIEJhdHRlcmllcyINCmNvbWJpbmVkX3Jldmlld3MgPC0gcmJpbmQoYWxsX2ZpcmVfcmV2aWV3c19yYXRpbmdzLGFsbF9raW5kbGVfcmV2aWV3c19yYXRpbmdzLGFsbF9iYXR0ZXJ5X3Jldmlld3NfcmF0aW5ncykNCmdncGxvdChjb21iaW5lZF9yZXZpZXdzLCBhZXMocmV2aWV3cy5yYXRpbmcsIGZpbGwgPSBJdGVtKSkgKyBnZW9tX2RlbnNpdHkoYWxwaGEgPSAwLjUsIHBvc2l0aW9uID0gJ2lkZW50aXR5JykgKyB0aGVtZShsZWdlbmQucG9zaXRpb249InJpZ2h0IikgKyBnZ3RpdGxlKCJDb21wYXJpc29uIG9mIFVzZXIgUmF0aW5ncyIpICsgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpIA0KDQpgYGANCg0KDQpBbGwgdGhlIGFuYWx5c2lzIGFuZCBncmFwaHMgcG9zdGVkIGFib3ZlIHByb3ZpZGUgc29tZSBpbnRlcmVzdGluZyBhbmQgdXNlZnVsIGluZm9ybWF0aW9uIHdpdGggcmVzcGVjdCB0byBBbWF6b24gc3VwcGxpZWQgcHJvZHVjdHMgYW5kIHRoZSBjb25zdW1lciBiZWhhdmlvciB3aGVuIGl0IGNvbWVzIHRvIHB1cmNoYXNpbmcgKHBvcHVsYXJpdHkgYmFzZWQgb24gdGhlIHRpbWUpLiBVbmxpa2UgdGhlIGdlbmVyYWwgcGVyY2VwdGlvbiwgRmV3IGFtYXpvbiBwcm9kdWN0cyBsaWtlIEZpcmUgdGFibGV0cyBhcmUgcXVpdGUgcG9wdWxhciBhbmQgdGFyZ2V0ZWQgdG93YXJkcyBhIG5pY2hlIHNlZ21lbnQgYW5kIHNvbGQgdmVyeSBmcmVxdWVudGx5IGR1cmluZyB0aGUgaG9saWRheXMuICANCg==